This entry is about creating Data Templates. A data template is basically a template that lets you define the visual structure of a control. With a data template you can change the look and feel of any control, typically in container controls like ListBox and ItemsControl (controls that hold a collection of items). This is when data templates are utilized to it’s full potential.
In this post, I have created a pseudo business application that allows you to select a product and quantity, and add that to a ListBox re-defined with a data template. This is what it looks like.
In this sample, I have used 2 data templates for the ListBoxItem, a normal template and one for when then ListBoxItem is selected. If you look at the screenshot, when the item is selected, you see more details and a “delete button”, whereas the others have a default look. Here’s the Xaml for the default data template.
<DataTemplate x:Key="ListBoxItemTemplate" DataType="{x:Type local:Product}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" FontWeight="Bold" Grid.Column="0" Grid.Row="0" Margin="5" />
<TextBlock Text="{Binding Path=QtyOrdered, StringFormat=Quantity: \{0\}}"
Grid.Column="1" Grid.Row="0" Margin="5" />
</Grid>
</DataTemplate>
Here’s the Xaml for the ListBoxItem‘s Selected data template.
<DataTemplate x:Key="SelectedListBoxItemTemplate" DataType="{x:Type local:Product}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0" Orientation="Vertical" >
<TextBlock Text="Name" FontWeight="Bold" />
<TextBlock Margin="10,0,0,0" >
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} (Model Number: {1})" >
<Binding Path="Name" />
<Binding Path="ModelNo" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
<StackPanel Grid.Column="0" Grid.Row="1" Orientation="Vertical" >
<TextBlock Text="Description" FontWeight="Bold" />
<TextBlock Text="{Binding Path=Description}" Margin="10,0,0,0" />
</StackPanel>
<StackPanel Grid.Column="1" Grid.RowSpan="3" Orientation="Horizontal"
HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,5,0" >
<TextBlock Text="Quantity: " />
<TextBlock Text="{Binding Path=QtyOrdered}" />
</StackPanel>
<Button Grid.Column="2" Grid.RowSpan="3" Command="Delete" CommandParameter="{Binding}"
HorizontalAlignment="Center" VerticalAlignment="center" Margin="5">
<Button.Content>
<Image Source="/WPFDataTemplate;component/delete-128x128.png" Width="32" Height="32" />
</Button.Content>
</Button>
</Grid>
</DataTemplate>
Now that we have our 2 data templates defined, we have to hook them up to the ListBox. What I’ve done is define a Style (as a resource) and used Style Triggers to set our data templates. The default data template is set as a style setter, and the selected data template is set on the style trigger for “IsSelected” property. Below is a snippet of the style.
<Style x:Key="ListBoxItemContainerStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="ContentTemplate" Value="{StaticResource ListBoxItemTemplate}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self},
Path=(ItemsControl.AlternationIndex), Converter={StaticResource BackgroundAlternationConverter}}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="ContentTemplate" Value="{StaticResource SelectedListBoxItemTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
Last of all, you just have to set the ListBox‘s ItemContainerStyle to the style defined in our resources, like so.
How to set Alternating Background for ListBox
On a side note, something of interest would be how to set alternating background color for the ListBox as seen in the screenshot. Since ListBox derives from an ItemsControl, there’s a property you can use called ItemsControl.AlternationCount property. Used together with ItemsControl.AlternatingIndex (a Static DependencyProperty), and a AlternationConverter, you can create alternating backgrounds for the ListBox, like so.
<AlternationConverter x:Key="BackgroundAlternationConverter"> <SolidColorBrush>AliceBlue</SolidColorBrush> <SolidColorBrush>LightBlue</SolidColorBrush> </AlternationConverter> <!-- set this in your <Style> resource --> <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=(ItemsControl.AlternationIndex), Converter={StaticResource BackgroundAlternationConverter}}" />
There we have it, a straightforward, fun and efficient way to make use of data templates to tweak visual appearances and perform data-binding to our data models. Happy Coding.
Download the sample solution here.
Share this post: |
June 12, 2009 at 1:56 pm
[…] the ability to change the look of any control, and still keeping its original functionality. In my previous blog post, I talked about how create Data Templates. This post, we are going to explore the world of Control […]